package com.irssproject.app.dao.lectorRSS.impl;

import com.irssproject.app.dao.lectorRSS.iface.SubscriptionsDAO;
import com.irssproject.app.entitats.*;
import com.irssproject.app.entitats.recommendations.TopicSubscription;
import com.irssproject.app.entitats.recommendations.UserSubscription;
import java.sql.Timestamp;
import java.util.*;
import org.hibernate.Hibernate;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class SubscriptionsDAOHibernate extends HibernateDaoSupport implements
        SubscriptionsDAO {

    @Override
    public List<Subscription> getListSubscripcions(User usuari, Boolean fromRecommendation) {
        DetachedCriteria criteria = DetachedCriteria.forClass(Subscription.class);
        criteria.add(Restrictions.eq("user", usuari));
        criteria.addOrder(Order.asc("label"));

        if (fromRecommendation != null) {
            criteria.add(Restrictions.eq("fromRecommendation", fromRecommendation));
        }

        return (List<Subscription>) getHibernateTemplate().findByCriteria(criteria);

    }

    @Override
    public void insertSubscription(Subscription subscripcio) {
        getHibernateTemplate().save(subscripcio);
    }

    @Override
    public void deleteSubscripcio(Long idSubscripcio) {
        Subscription subscripcio = (Subscription) getHibernateTemplate().get(
                Subscription.class, idSubscripcio);
        getHibernateTemplate().delete(subscripcio);
    }

    @Override
    public List<Reading> getAllReadingsOnInterval(Subscription subs, Integer toElement) {
        DetachedCriteria criteria = DetachedCriteria.forClass(Reading.class);
        criteria.add(Restrictions.eq("subscription", subs));
        criteria.addOrder(Order.desc("addedDate"));
        List<Reading> rdngLst = getHibernateTemplate().findByCriteria(criteria);
        logger.info("returning readings lst to element " + (toElement > rdngLst.size() ? rdngLst.size() : toElement));
        return rdngLst.subList(0, toElement > rdngLst.size() ? rdngLst.size() : toElement);
    }

    @Override
    public List<Reading> getReadingsOnInterval(Subscription subs, Integer toElement) throws Exception {

        DetachedCriteria criteria = DetachedCriteria.forClass(Reading.class);
        criteria.add(Restrictions.eq("subscription", subs));
        criteria.add(Restrictions.eq("read", Boolean.FALSE));
        criteria.addOrder(Order.desc("addedDate"));
        List<Reading> rdngLst = getHibernateTemplate().findByCriteria(criteria);
        logger.info("returning readings lst to element " + (toElement > rdngLst.size() ? rdngLst.size() : toElement));
        List<Reading> lst = rdngLst.subList(0, toElement > rdngLst.size() ? rdngLst.size() : toElement);
        for (Reading rdn : lst) {
            logger.info("returning reading " + rdn.getId() + " with title " + rdn.getItem().getTitle());
        }
        return lst;
    }

    @Override
    public void markItemAsReaded(Reading reading, int numItems) {
        reading.setRead(true);
        reading.getSubscription().setUnreadItemsNumber(numItems);
        logger.info("Marked read ---> " + reading.getItem().getTitle());
        getHibernateTemplate().saveOrUpdate(reading);
    }

    @Override
    public List<Reading> getStarredReadingsOnInterval(User usuari, Integer toElement) throws Exception {

        DetachedCriteria criteria = DetachedCriteria.forClass(Reading.class);
        criteria.createCriteria("subscription").add(Restrictions.eq("user", usuari));
        criteria.add(Restrictions.eq("liked", Boolean.TRUE));
        criteria.addOrder(Order.desc("addedDate"));
        List<Reading> rdngLst = getHibernateTemplate().findByCriteria(criteria);
        if (rdngLst.size() > 0) {
            if (toElement != null) {
                logger.info("returning readings lst to element " + (toElement > rdngLst.size() ? rdngLst.size() : toElement));
                return rdngLst.subList(0, toElement > rdngLst.size() ? rdngLst.size() : toElement);
            } else {
                logger.info("returning all readings total: " + rdngLst.size());
                return rdngLst;
            }

        } else {
            logger.info("returning readings lst is empty");
            return null;
        }
    }

    @Override
    public Date getDataDarrerItem(Subscription subscripcio) {
        return (Date) getHibernateTemplate().find("select max(i.publishedDate) from Reading l join l.item i join l.subscription s where s = ?", subscripcio);
    }

    @Override
    public Item getItem(Item item) {
        return (Item) getHibernateTemplate().get(Item.class, item.getId());
    }

    @Override
    public void definirRellevanciaDeLectura(Reading lectura) {
        getHibernateTemplate().saveOrUpdate(lectura);
    }

    @Override
    public Integer getNumItemsSubscripcio(Subscription subscripcio) {
        return (Integer) getHibernateTemplate().find(
                "from Item it where it.subscription = ?", subscripcio).size();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Label> getListEtiquetes(User usuari) {
        return (List<Label>) getHibernateTemplate().find("select distinct(s.label) from Subscription s where s.user = ?",
                usuari);
    }

    @Override
    public Subscription getSubscripcioByFeedLink(User usuari, String feedLink) {
        return (Subscription) getHibernateTemplate().find(
                "from Subscription s where s.feed.link = ? and s.user = ?",
                new Object[]{feedLink, usuari}).get(0);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Feed getUserFeed(User usuari, String feedLink) {
        List<Subscription> s = (List<Subscription>) getHibernateTemplate().find(
                "from Subscription s where s.feed.link = ? and s.user = ?",
                new Object[]{feedLink, usuari});

        return (s != null && s.size() == 1 ? s.get(0).getFeed() : null);
    }

    @Override
    public Subscription getSubscripcioById(Long idSubscripcio) {
        Subscription sub = (Subscription) getHibernateTemplate().get(
                Subscription.class, idSubscripcio);
        return sub;
    }

    @Override
    public void refreshSubscripcio(Subscription subscripcio) {
        getHibernateTemplate().saveOrUpdate(subscripcio);
    }

    @Override
    public Reading getLecturaById(Long idLectura) {
        return (Reading) getHibernateTemplate().get(Reading.class, idLectura);
    }

    @Override
    public void insertItems(List<Item> items) {
        getHibernateTemplate().saveOrUpdateAll(items);

    }

    @SuppressWarnings("unchecked")
    @Override
    public Item getItemByLink(String link) {
        List<Item> listItem = (List<Item>) getHibernateTemplate().find(
                "from Item item where item.link = ?", link);

        if (listItem.size() > 0) {
            return listItem.get(0);
        } else {
            return null;
        }
    }

    @Override
    public Long insertItem(Item item) {
        return (Long) getHibernateTemplate().save(item);
    }

    @Override
    public Timestamp getDarreraDataPublicacio(Subscription subscripcio) {
        return (Timestamp) getHibernateTemplate().find("select max(i.publishedDate) from Reading l join l.item i join l.subscription s where s = ?", subscripcio).get(0);
    }

    @Override
    public boolean marcarLlegidaONoLlegida(Long idLectura) {
        Reading lectura = (Reading) getHibernateTemplate().get(Reading.class,
                idLectura);
        lectura.setRead(!lectura.isRead());
        getHibernateTemplate().update(lectura);
        return !lectura.isRead();
    }

    @Override
    public boolean valorarLectura(Long idLectura) {
        Reading lectura = (Reading) getHibernateTemplate().get(Reading.class,
                idLectura);
        lectura.setLiked(!lectura.isLiked());
        getHibernateTemplate().update(lectura);
        return !lectura.isLiked();

    }

    @Override
    public void marcarTotesLecturesLlegides(Long idSubscripcio) {

        Subscription sub = (Subscription) getHibernateTemplate().get(
                Subscription.class, idSubscripcio);

        Iterator<Reading> it = sub.getReadings().iterator();
        while (it.hasNext()) {
            it.next().setRead(true);
        }
        getHibernateTemplate().update(sub);
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Reading> getLecturesBySubscripcioId(Long idSubscripcio) {
        return (List<Reading>) getHibernateTemplate().find(
                "from Reading l where l.subscription.id = ?",
                idSubscripcio);
    }

    @Override
    public Item getItemById(Long id) {
        return (Item) getHibernateTemplate().get(Item.class, id);
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Reading> getReadingsOnPeriod(Date from, Date since, Long id) {

        return (List<Reading>) getHibernateTemplate().find("from Reading lect where lect.item.publishedDate > ? and lect.item.publishedDate <= ? and lect.subscription.id = ?", new Object[]{from, since, id});
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Reading> getTopLecturesBySubscripcioId(Long id, int clusteringReadingsSize) {

        DetachedCriteria criteria = DetachedCriteria.forClass(Reading.class);
        criteria.createCriteria("subscription").add(Restrictions.eq("id", id));
        criteria.createCriteria("item").addOrder(Order.desc("publishedDate"));
        return getHibernateTemplate().findByCriteria(criteria, 0, clusteringReadingsSize);
//		return (List<Reading>) getHibernateTemplate().find("from Reading lectura where lectura.subscripcio.id = ? order by lect.item.dataPublicacio", id);
    }

    @Override
    public void updateSubscripcio(Subscription subscripcio) {
        getHibernateTemplate().update(subscripcio);
    }

    @Override
    public List<User> getUsersSubscribed(User connectedUser) {
        List<User> liUsers = new ArrayList<User>();
        List<UserSubscription> liUserSubs = getHibernateTemplate().find("from UserSubscription where idUser = ?", connectedUser.getId());
        for (UserSubscription user : liUserSubs) {
            liUsers.add((User) getHibernateTemplate().get(User.class, user.getUserSubscriptionPK().getIdUser_subscribed()));
        }
        return liUsers;
    }

    @Override
    public List<Topic> getTopicsSubscribed(User connectedUser) {
        List<Topic> liTopics = new ArrayList<Topic>();
        List<TopicSubscription> liTopicsSubs = getHibernateTemplate().find("from TopicSubscription where idUser = ?", connectedUser.getId());
        for (TopicSubscription topic : liTopicsSubs) {
            liTopics.add((Topic) getHibernateTemplate().get(Topic.class, topic.getTopicSubscriptionPK().getIdTopic_subscribed()));
        }
        return liTopics;
    }

    @Override
    public void insertReading(Reading reading) {
        getHibernateTemplate().save(reading);
    }

    @Override
    public boolean existsReading(Subscription subs, Item item) {
        return getHibernateTemplate().find("from Reading l where l.subscription = ? and l.item = ?", new Object[]{subs, item}).size() > 0 ? true : false;
    }

    @Override
    public List<Feed> getFeedsLstByTopic(User user, Topic topic) {

        List<Feed> feedsLst = new ArrayList<Feed>();
        for (Subscription sbs : user.getSubscripcions()) {
            feedsLst.add(sbs.getFeed());
        }

        String query = "select distinct f from ReadingProfile pf join pf.feed f where pf.topic = ? and pf.user != ?";
        Object[] params = new Object[2/*
                 * +feedsLst.size()
                 */];
        params[0] = topic;
        params[1] = user;
//        
//        if (feedsLst.size()>0) {
//            query += " and f.id not in (?";
//            for (int i=1;i<feedsLst.size();i++) {
//                params[i+2] = feedsLst.get(i).getId();
//                query += ",?";
//            }
//            query += ")";
//        }

        List<Feed> lst = getHibernateTemplate().find(query, params);
        return lst;
    }

    @Override
    public List<Topic> getTopicLstLikeName(String topic) {

        String topicAux = "%" + topic.toLowerCase() + "%";
        List<Topic> topicLst = (List<Topic>) getHibernateTemplate().find("SELECT c FROM Topic c WHERE Lower(c.valor) like ?", topicAux);
        return topicLst;
    }

    @Override
    public List<Item> getItemsLstByTopic(User user, Topic topic) {

//        List<Subscription> sbsLst = (List<Subscription>)getHibernateTemplate().find("select s from Subscription s join fetch s.readings where s.user = ?", user);
//        List<Item> itemsLst = new ArrayList<Item>();
//        
//        for (Subscription sbs: sbsLst)
//            for (Reading rdng : sbs.getReadings())
//                itemsLst.add(rdng.getItem());
//        
        String query = "select distinct i from ReadingProfile pf join pf.item i where pf.topic = ? and pf.user != ?";
        Object[] params = new Object[2];
        
        params[0] = topic;
        params[1] = user;
//        
//        if (itemsLst.size()>0) {
//            query += " and i.id not in (?";
//            for (int i=1;i<itemsLst.size();i++) {
//                params[i+2] = itemsLst.get(i).getId();
//                query += ",?";
//            }
//            query += ")";
//        }

        List<Item> lst = getHibernateTemplate().find(query, params);
        return lst;
    }
}
